﻿using System;
using System.IO;
using System.Text;
using System.Windows;
using AOC19NET.Classes;
using AOC19NET.Controls;
using System.Diagnostics;
using System.Windows.Media;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
using System.Runtime.InteropServices;


namespace AOC19NET {
	/// <summary>
	/// Winamp's current info class.
	/// </summary>
	class WinampPage {
		/*-------------------------------------------------------------------------*/
		/* DEFINITIONS															   */
		/*-------------------------------------------------------------------------*/
		#region DEFINITIONS
			
		#endregion

		/*-------------------------------------------------------------------------*/
		/* MEMBERS																   */
		/*-------------------------------------------------------------------------*/
		#region MEMBERS
		/// <summary>
		/// Custom control containing all the elements on the LCD screen
		/// </summary>
		public MainControlBigPic m_MainControl;

		/// <summary>
		/// Utility to read information from the Winamp process.
		/// </summary>
		private WinampReader m_WinampReader;

		/// <summary>
		/// Stores the last second that Winamp window was checked.
		/// </summary>
		private int m_iLastWinampCheck;

		/// <summary>
		/// Full path of the current song. We'll only update the ID3 info if it changes.
		/// </summary>
		private String m_sCurrentSong;

		/// <summary>
		/// Store the status of the Winamp application.
		/// </summary>
		private bool m_bWinampRunning;
		#endregion

		/*-------------------------------------------------------------------------*/
		/* METHODS																   */
		/*-------------------------------------------------------------------------*/
		#region METHODS
		/// <summary>
		/// Constructor of the class: sets all the members to its default values.
		/// </summary>
		public WinampPage() {
			// Initialize the Winamp Utility
			m_WinampReader = new WinampReader();
			m_bWinampRunning = false;

			// Initialize custom controls
			m_MainControl = new MainControlBigPic();
			ClearScreen();
		}

		/*-------------------------------------------------------------------------*/
		/* MAIN METHODS															   */
		/*-------------------------------------------------------------------------*/
		/// <summary>
		/// Actions to do once at the beginning.
		/// </summary>
		public void Init() {
			// Check for Winamp's presence
			m_WinampReader.FindWinamp();
		}

		/// <summary>
		/// Actions to do during the update process.
		/// To be called periodically.
		/// </summary>
		public void Run() {
			// Check if Winamp is still running (each 3 secs)
			int iCurrentSecs = DateTime.Now.Second;
			if(Math.Abs(iCurrentSecs - m_iLastWinampCheck) > 3) {
				bool bWinampRunning = m_WinampReader.FindWinamp();
				m_iLastWinampCheck = iCurrentSecs;

				// If it comes from not running, reset LCD screen.
				if(bWinampRunning && !m_bWinampRunning) {
					m_MainControl.m_TextBoxTitle.Text = "";
					m_MainControl.m_ImageBorder.Visibility = Visibility.Visible;
					m_MainControl.m_Img.Visibility = Visibility.Visible;
					m_MainControl.m_ImgSmall.Visibility = Visibility.Visible;
				}
				m_bWinampRunning = bWinampRunning;
			}

			// Check if a new song is playing
			String sNewSong = m_WinampReader.GetPlayingTrackPath();
			if(sNewSong != m_sCurrentSong && sNewSong != "ERROR" && sNewSong != "") {
				m_sCurrentSong = sNewSong;
				ReadNewSong();
			}

			// If the same song is playing, update progress bar
			else if(sNewSong != "ERROR") {
				TimeSpan Elapsed = m_WinampReader.GetElapsedTime();
				TimeSpan Total = m_WinampReader.GetTotalTime();
				double dPercent = Elapsed.TotalSeconds/Total.TotalSeconds;
				m_MainControl.m_ProgressFill.Width = dPercent * m_MainControl.m_ProgressBckg.Width;
				m_MainControl.m_ProgressElapsedText.Text = String.Format("{0:00}:{1:00}", Elapsed.Minutes, Elapsed.Seconds);
				m_MainControl.m_ProgressTotalText.Text = String.Format("{0:00}:{1:00}", Total.Minutes, Total.Seconds);
			}

			// If Winamp could not be found or some error ocurred getting song filename, clear screen
			else if(sNewSong == "ERROR") {
				ClearScreen();
			}
		}

		/// <summary>
		/// Actions to do during the render process, typically update the graphics.
		/// To be called periodically.
		/// </summary>
		public void Render() {
			// Update the Date and hour field
			m_MainControl.m_LabelHour.Content = DateTime.Now.ToString("HH:mm");
			m_MainControl.m_LabelDate.Content = DateTime.Now.ToString("dd/MM/yyyy");
		}

		/// <summary>
		/// Changes the current color scheme.
		/// </summary>
		/// <param name="_NewBaseColor">The base color for the new color scheme.</param>
		public void ChangeColorScheme(Color _NewBaseColor) {
			m_MainControl.m_TextBoxTitle.Foreground			= Tint(_NewBaseColor, 0.5f,		1.0f);
			m_MainControl.m_LabelHour.Foreground			= Tint(_NewBaseColor, 0.25f,	0.3f);
			m_MainControl.m_LabelDate.Foreground			= Tint(_NewBaseColor, 0.4f,		0.8f);
			m_MainControl.m_ProgressElapsedText.Foreground	= Tint(_NewBaseColor, 0.2f,		1.0f);
			m_MainControl.m_ProgressTotalText.Foreground	= Tint(_NewBaseColor, 0.2f,		1.0f);
			m_MainControl.m_ProgressBckg.Fill				= Tint(_NewBaseColor, 0.55f,	0.5f);
			m_MainControl.m_ProgressFill.Fill				= Tint(_NewBaseColor, 0.55f,	0.5f);
		}

		/*-------------------------------------------------------------------------*/
		/* UTILS AND AUXILIAR METHODS											   */
		/*-------------------------------------------------------------------------*/
		/// <summary cref="m_sCurrentSong">
		/// Read the ID3 tag from the song specified in m_sCurrentSong.
		/// </summary>
		private void ReadNewSong() {
			// We'll be using the TagLib library for C# to read the ID3 Tags
			try {
				// 1. Read the ID3v2 Tag
				TagLib.File SongFile = TagLib.File.Create(m_sCurrentSong);
				TagLib.Id3v2.Tag NewTag = (TagLib.Id3v2.Tag)SongFile.GetTag(TagLib.TagTypes.Id3v2);

				if(NewTag == null)
					return;

				// 2. Get Title, Artist, Album and Year tags
				m_MainControl.m_TextBoxTitle.Text = NewTag.Title;
				m_MainControl.m_TextBoxArtist.Text = NewTag.Performers[0];
				m_MainControl.m_TextBoxAlbum.Text = NewTag.Album;
				m_MainControl.m_TextBoxYear.Text = NewTag.Year.ToString();

				// 3. Get Picture
				foreach(TagLib.IPicture CoverImage in NewTag.Pictures) {
					byte[] ImageData = CoverImage.Data.Data;
					MemoryStream ImageStream = new MemoryStream(ImageData);
					BitmapImage NewImage = new BitmapImage();
					NewImage.BeginInit();
					NewImage.StreamSource = ImageStream;
					NewImage.EndInit();
					m_MainControl.m_Img.Source = NewImage;
					m_MainControl.m_ImgSmall.Source = NewImage;
				}

				// Add support for those files without image (just put an empty image)
				if(NewTag.Pictures.Length == 0) {
					BitmapImage EmptyImage = new BitmapImage();
					m_MainControl.m_Img.Source = EmptyImage;
					m_MainControl.m_ImgSmall.Source = EmptyImage;
				}
			} catch(Exception e) {
				Console.WriteLine("\nERROR");
				Console.WriteLine("\t Exception parsing the ID3 tag for the file {0}", m_sCurrentSong);
				Console.WriteLine(e);
				Console.WriteLine("ERROR\n");
			}
		}

		/// <summary>
		/// Reset all the fields from the LCD screen.
		/// </summary>
		private void ClearScreen() {
			m_MainControl.m_TextBoxTitle.Text = "Please, start Winamp";
			m_MainControl.m_TextBoxArtist.Text = "";
			m_MainControl.m_TextBoxAlbum.Text = "";
			m_MainControl.m_TextBoxYear.Text = "";
			m_MainControl.m_ProgressElapsedText.Text = "00:00";
			m_MainControl.m_ProgressTotalText.Text = "00:00";
			m_MainControl.m_ProgressFill.Width = 0;
			m_MainControl.m_Img.Visibility = Visibility.Hidden;
			m_MainControl.m_ImgSmall.Visibility = Visibility.Hidden;
			m_MainControl.m_ImageBorder.Visibility = Visibility.Hidden;

			// Reset also stored values
			m_sCurrentSong = "NO_SONG";
		}

		/// <summary>
		/// Sets the GMail unread messages label. If it's more than 0, the label will be bold-style.
		/// </summary>
		/// <param name="_iUnreadMessages">New amount of unread messages.</param>
		public void SetUnread(int _iUnreadMessages) {
			m_MainControl.m_LabelUnread.Content = String.Format("({0})", _iUnreadMessages);
			if(_iUnreadMessages > 0) {
				m_MainControl.m_LabelUnread.FontWeight = FontWeights.Bold;
			} else {
				m_MainControl.m_LabelUnread.FontWeight = FontWeights.Normal;
			}
		}

		/// <summary>
		/// Wrapper for the ColorHelper.Tint() method.
		/// This one will set the alpha component to the given value and return the new color
		/// in the form of a <see cref="SolidColorBrush"/>.
		/// </summary>
		/// <param name="_BaseColor">Base color.</param>
		/// <param name="_fTintLevel">Tint level. See <see cref="ColorHelper.Tint"/> for more info.</param>
		/// <param name="_fAlpha">Alpha component of the new color.</param>
		/// <returns>Solid brush initialized with the tinted color.</returns>
		private SolidColorBrush Tint(Color _BaseColor, float _fTintLevel, float _fAlpha) {
			Color NewColor = ColorHelper.Tint(_BaseColor, _fTintLevel);
			NewColor.ScA = _fAlpha;
			return new SolidColorBrush(NewColor);
		}
		#endregion
	}
}
